package tps12.axwax.server;

import java.io.BufferedReader;
import java.io.IOException;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.servlet.http.HttpServletResponse;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import tps12.axwax.server.data.BarredRectangularPuzzle;
import tps12.axwax.server.data.PuzzleStore;
import tps12.axwax.server.data.UserSolution;

import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;

public class PuzzleHandler extends HttpHandler {
	
	final Logger log = Logger.getLogger(PuzzleHandler.class.getName());
	
	final PuzzleStore.Factory psf;
	
	public PuzzleHandler(PuzzleStore.Factory factory) { psf = factory; }
	
	/* (non-Javadoc)
	 * @see tps12.axwax.server.HttpHandler#get(java.lang.String)
	 */
	@Override
	public Result get(String pathInfo) {
		PuzzleStore ps = psf.get();
		if (pathInfo.equals("/"))
			return new Result(HttpServletResponse.SC_OK, Result.JSON, getList(ps, ps.list()));
		else {
			String[] path = pathInfo.split("/");
			
			if (path.length > 2 && path[2].equals("letters"))
				return new Result(HttpServletResponse.SC_OK, Result.JSON, getPuzzleLetters(path[1], ps));
			else
				return new Result(HttpServletResponse.SC_OK, Result.JSON, getPuzzle(path[1], ps));
		}
	}
	
	/* (non-Javadoc)
	 * @see tps12.axwax.server.HttpHandler#put(java.lang.String, java.lang.String)
	 */
	@Override
	public Result put(String pathInfo, BufferedReader r) { 
		PuzzleStore ps = psf.get();
		String data;
		try {
			data = r.readLine();
		} catch (IOException e1) {
			log.log(Level.WARNING, "Failed to read content", e1);
			ps.close();
			return new Result(HttpServletResponse.SC_BAD_REQUEST);
		}
		
		String[] path = pathInfo.split("/");
		if (path.length > 2 && path[2].equals("letters")) {
		    UserService userService = UserServiceFactory.getUserService();
		    if (userService.isUserLoggedIn()) {
		    	String key = path[1];
				BarredRectangularPuzzle p;
				try {
					p = ps.getPuzzle(KeyFactory.stringToKey(key));
				} catch (IllegalArgumentException e) {
					log.log(Level.WARNING, "Badly formatted key: " + key, e);
					ps.close();
					return new Result(HttpServletResponse.SC_BAD_REQUEST);
				}
				if (p == null) {
					log.log(Level.WARNING, "Puzzle key not found: " + key);
					ps.close();
					return new Result(HttpServletResponse.SC_BAD_REQUEST);
				}
		    	putPuzzleLetters(userService.getCurrentUser(), ps, p, data);
		    	return new Result(HttpServletResponse.SC_OK);
		    }
		}
		return new Result(HttpServletResponse.SC_NOT_FOUND);
	}

	String getPuzzle(String key, PuzzleStore ps) {
		BarredRectangularPuzzle p;
		try {
			p = ps.getPuzzle(KeyFactory.stringToKey(key));
		} catch (IllegalArgumentException e) {
			log.log(Level.WARNING, "Badly formatted key: " + key, e);
			ps.close();
			return "";
		}
		if (p == null) {
			log.log(Level.WARNING, "Puzzle key not found: " + key);
			ps.close();
			return "";
		}
		ps.close();
		return p.toJSONString();
	}


	String getPuzzleLetters(String key, PuzzleStore ps) {
		BarredRectangularPuzzle p;
		try {
			p = ps.getPuzzle(KeyFactory.stringToKey(key));
		} catch (IllegalArgumentException e) {
			log.log(Level.WARNING, "Badly formatted key: " + key, e);
			ps.close();
			return "";
		}
		if (p == null) {
			log.log(Level.WARNING, "Puzzle key not found: " + key);
			ps.close();
			return "";
		}
		UserSolution solution = ps.getUserSolution(
				UserServiceFactory.getUserService().getCurrentUser(),
				p);
		ps.close();
		return solution != null ? solution.getLetters() : "";
	}

	void putPuzzleLetters(User user, PuzzleStore ps,
			BarredRectangularPuzzle puzzle, String data) {
		UserSolution solution = ps.getUserSolution(user, puzzle);
		solution.setLetters(data);
		ps.save(solution);
		ps.close();
	}

	String getList(PuzzleStore ps, List<BarredRectangularPuzzle> r) {
		try {
			JSONArray a = new JSONArray();
			for (int i = 0; i < r.size(); i++) {
				JSONObject p = new JSONObject();
				p.put("title", r.get(i).title());
				p.put("url", "/" + KeyFactory.keyToString(r.get(i).getKey()) + "/");
				a.put(p);
			}
			return a.toString();
		} catch (JSONException e) {
			log.log(Level.WARNING, "Creating JSON array failed", e);
			return "";
		}
		finally {
			ps.close();
		}
	}
	
	/* (non-Javadoc)
	 * @see tps12.axwax.server.HttpHandler#post(java.lang.String, java.io.Reader)
	 */
	@Override
	public Result post(String pathInfo, BufferedReader body) {
		if (!pathInfo.equals("/"))
			return new Result(HttpServletResponse.SC_NOT_FOUND);
		
	    UserService userService = UserServiceFactory.getUserService();
	    if (userService.isUserLoggedIn() && userService.isUserAdmin()) {
			BarredRectangularPuzzle puzzle = BarredRectangularPuzzle.FromXml(body);
			if (puzzle != null) {
				PuzzleStore ps = psf.get();
				ps.save(puzzle);
				ps.close();
				return new Result(HttpServletResponse.SC_CREATED, Result.TEXT,
						"/" + KeyFactory.keyToString(puzzle.getKey()) + "/");
			}
	    }
		return new Result(HttpServletResponse.SC_FORBIDDEN);
	}
}
